home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Gekkan Dennou Club 147
/
Gekkan Dennou Club - 2000.8 Vol. 147 (Japan).7z
/
Gekkan Dennou Club - 2000.8 Vol. 147 (Japan) (Track 1).bin
/
docs
/
ippon
/
ver
/
013
/
enemy.c
next >
Wrap
C/C++ Source or Header
|
2000-07-07
|
6KB
|
274 lines
/* enemy.c */
#include <stdio.h>
#include <xsp2lib.h>
#include "main.h"
#include "player.h"
#include "shot.h"
#include "enemy.h"
#include "eshot.h"
#include "effect.h"
#include "psearch.h"
#define ENEMY_MAX 32 /* 敵最大数 */
static ENEMY enemy[ENEMY_MAX]; /* ワーク */
static ENEMY *enemy_top, /* 使用中のワークのリスト */
*enemy_null_top, /* 空のワークのリスト */
*enemy_end; /* 使用中ワークのリストの末尾 */
/* 関数プロトタイプ宣言 */
void EnemyAllocA (ENEMY *);
int EnemyMoveA (ENEMY *);
void EnemyAllocB (ENEMY *);
int EnemyMoveB (ENEMY *);
/* 初期化関数へのポインタの配列 */
typedef void (*enemy_alloc) (ENEMY *);
enemy_alloc EnemyAllocFunc[] =
{
EnemyAllocA,
EnemyAllocB,
};
/* 移動関数へのポインタの配列 */
typedef int (*enemy_move) (ENEMY *);
enemy_move EnemyMoveFunc[] =
{
EnemyMoveA,
EnemyMoveB,
};
/* タイプAの敵の初期化ルーチン */
void EnemyAllocA (ENEMY * p)
{
p->pt = obj_zako02 + 15;
p->info = 0x0700 | PRIORITY_ZAKO; /* 数値を決めうちして入れるのはよくない */
p->hit_sx = 12; /* 自機ショットに対する当たり判定 */
p->hit_sy = 12;
p->hp = 1; /* 耐久力 */
p->damage = 0;
}
/* タイプAの敵の移動ルーチン */
/* 返り値:非0なら消去 */
int EnemyMoveA (ENEMY * p)
{
/* 敵をくるくる回すアニメーション */
p->pt--;
if (p->pt < obj_zako02)
p->pt = obj_zako02 + 15;
/* X座標を自機に近づける */
if (p->lx > player->lx)
p->lx -= 32768;
else
p->lx += 32768;
p->ly += 2 * 65536;
/* 上位ワード(固定整数部)だけ取り出す */
p->x = p->lx >> 16;
p->y = p->ly >> 16;
if (p->y > 256 + 32)
return (-1); /* Y座標が 256+32 以上なら消去 */
/* もし前回ダメージを受けたなら */
if (p->damage) {
p->hp -= p->damage;
p->damage = 0;
/* 耐久力が0以下なら消去 */
if (p->hp <= 0) {
EffectAlloc (EFFECT_EXPLZAKO, 0, p->x, p->y); /* 爆発パターンを出現させる */
return (-1);
}
}
xobj_set_st (p); /* 表示 */
return (0);
}
/* タイプBの敵の初期化ルーチン */
void EnemyAllocB (ENEMY * p)
{
p->pt = obj_zako02;
p->info = 0x0800 | PRIORITY_ZAKO; /* 数値を決めうちして入れるのはよくない */
p->hit_sx = 12; /* 自機ショットに対する当たり判定 */
p->hit_sy = 12;
p->hp = 2; /* 耐久力 */
p->damage = 0;
p->s_work = 0; /* ショット用ワークを初期化 */
}
/* タイプBの敵の移動ルーチン */
/* 返り値:非0なら消去 */
int EnemyMoveB (ENEMY * p)
{
/* 敵をくるくる回すアニメーション */
p->pt++;
if (p->pt > obj_zako02 + 15)
p->pt = obj_zako02;
/* X座標を自機に近づける */
if (p->lx > player->lx)
p->lx -= 32768;
else
p->lx += 32768;
p->ly += 2 * 65536;
/* 上位ワード(固定整数部)だけ取り出す */
p->x = p->lx >> 16;
p->y = p->ly >> 16;
/* 弾を撃つ処理(30フレームに1回発射) */
if (p->s_work++ > 30) {
char angle;
p->s_work = 0;
angle = psearch (p->x, p->y); /* 敵から見た自機の方向を unsigned char で返す */
EshotAlloc (0, p->x, p->y, 10, angle); /* 弾を撃つ */
}
if (p->y > 256 + 32)
return (-1); /* Y座標が 256+32 以上なら消去 */
/* もし前回ダメージを受けたなら */
if (p->damage) {
p->hp -= p->damage;
p->damage = 0;
/* 耐久力が0以下なら消去 */
if (p->hp <= 0) {
EffectAlloc (EFFECT_EXPLZAKO, 0, p->x, p->y); /* 爆発パターンを出現させる */
return (-1);
}
}
xobj_set_st (p); /* 表示 */
return (0);
}
/* ゲーム開始時に呼ばれる */
void EnemyInit (void)
{
int i;
/* リストをつなげる */
enemy_top = NULL;
enemy_end = NULL;
enemy_null_top = enemy;
for (i = 0; i < ENEMY_MAX; i++)
enemy[i].next = &enemy[i + 1];
enemy[ENEMY_MAX - 1].next = NULL;
}
/* 敵出現時に呼ばれる */
void EnemyAlloc (short type, signed short x, signed short y)
{
ENEMY *p;
if (enemy_null_top == NULL)
return; /* 空きのワークがない(キャラクターオーバー) */
/* リストの末尾に新しいノードを追加(他とは違うので注意) */
p = enemy_null_top;
enemy_null_top = p->next;
if (enemy_top == NULL)
enemy_top = p;
else
enemy_end->next = p;
p->next = NULL;
enemy_end = p;
p->type = type;
p->lx = x << 16;
p->ly = y << 16;
/* 関数へのポインタを使って分岐 */
/* type が 0 なら EnemyAllocA() が、1 なら EnemyAllocB() が実行される */
EnemyAllocFunc[p->type] (p);
return;
}
/* 垂直同期ごとに呼ばれる */
void EnemyMove (void)
{
ENEMY *p, *q;
signed short pl_x = player->x, pl_y = player->y;
p = enemy_top; /* 現在注目しているワーク */
q = NULL; /* 1つ前のワーク(ワーク削除時に必要) */
while (p != NULL) {
/* 敵キャラの移動ルーチン */
/* 関数へのポインタを使って分岐 */
/* type が 0 なら EnemyMoveA() が、1 なら EnemyMoveB() が実行される */
if (EnemyMoveFunc[p->type] (p)) { /* 返り値が非0なら消去 */
if (q == NULL) { /* リストの一番最初を削除 */
enemy_top = p->next;
p->next = enemy_null_top;
enemy_null_top = p;
q = NULL;
p = enemy_top;
} else {
if (p == enemy_end) { /* リストの一番最後を削除 */
q->next = NULL;
enemy_end = q;
p->next = enemy_null_top;
enemy_null_top = p;
p = q->next;
} else {
q->next = p->next;
p->next = enemy_null_top;
enemy_null_top = p;
p = q->next;
}
}
} else {
/* 敵キャラを消去しない場合 */
SHOT *p2 = shot_top; /* 現在注目しているショットのワーク */
signed short t;
/* プレイヤーとの当たり判定 */
if (((t = p->x + p->hit_sx) > pl_x)
&& ((t -= (short) (p->hit_sx << 1)) < pl_x)
&& ((t = p->y + p->hit_sy) > pl_y)
&& ((t -= (short) (p->hit_sy << 1)) < pl_y)) {
/* 当たった */
if (player->status == PLAYER_STATUS_ALIVE)
player->status = PLAYER_STATUS_DEAD;
}
/* ショットとの当たり判定 */
while (p2 != NULL) {
signed short p2_w;
short hit_w;
if (((t = p->x + (hit_w = p->hit_sx)) >= (p2_w = *((short *) (&p2->lx))))
&& ((t -= (short) (hit_w << 1)) <= p2_w)
&& ((t = p->y + (hit_w = p->hit_sy)) >= (p2_w = *((short *) (&p2->ly))))
&& ((t -= (short) (hit_w << 1)) <= p2_w)
&& (p2->damage == 0)) {
/* ショットが当たった */
p->damage++; /* 敵キャラにダメージを与える */
p2->damage = !0; /* 自機ショットに当たった事を知らせる */
}
p2 = p2->next;
}
q = p;
p = p->next;
}
}
}